package com.gitee.huanminabc.jcommon.multithreading.delay;

import lombok.Data;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 延迟消息包装类，实现 Delayed 接口用于延迟队列
 * 
 * 最重要的方法是 getDelay，用来判断是否到期
 * compareTo 方法用于排序，确保按执行时间顺序处理
 *
 * @author whd
 * @date 2017年9月24日 下午8:57:14
 */
@Data
public class MessageDelayed<T> implements Delayed {
    private static final AtomicLong ID_GENERATOR = new AtomicLong(0);
    
    private final long id;
    private final T body; // 消息内容
    private final long executeTime; // 执行时间（纳秒）

    /**
     * 创建延迟消息
     * @param body 消息内容
     * @param delayTimeMs 延迟时间（毫秒）
     */
    public MessageDelayed(T body, long delayTimeMs) {
        this(ID_GENERATOR.incrementAndGet(), body, delayTimeMs);
    }

    /**
     * 创建延迟消息
     * @param id 消息ID
     * @param body 消息内容
     * @param delayTimeMs 延迟时间（毫秒）
     */
    public MessageDelayed(long id, T body, long delayTimeMs) {
        if (delayTimeMs < 0) {
            throw new IllegalArgumentException("Delay time cannot be negative: " + delayTimeMs);
        }
        
        this.id = id;
        this.body = body;
        // 使用纳秒精度计算执行时间
        this.executeTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(delayTimeMs, TimeUnit.MILLISECONDS);
    }

    /**
     * 比较两个延迟消息的执行时间
     * 如果执行时间相同，则按ID排序
     */
    @Override
    public int compareTo(Delayed other) {
        if (other == this) {
            return 0;
        }
        
        if (other instanceof MessageDelayed) {
            MessageDelayed<?> otherMsg = (MessageDelayed<?>) other;
            long timeDiff = this.executeTime - otherMsg.executeTime;
            
            if (timeDiff != 0) {
                return timeDiff < 0 ? -1 : 1;
            }
            
            // 时间相同，按ID排序
            return Long.compare(this.id, otherMsg.id);
        }
        
        // 与其他类型的 Delayed 对象比较
        long diff = this.getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS);
        return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
    }

    /**
     * 获取剩余延迟时间
     * @param unit 时间单位
     * @return 剩余延迟时间，如果已到期则返回负数或0
     */
    @Override
    public long getDelay(TimeUnit unit) {
        long remaining = executeTime - System.nanoTime();
        return unit.convert(remaining, TimeUnit.NANOSECONDS);
    }

    /**
     * 检查消息是否已到期
     * @return true如果已到期
     */
    public boolean isExpired() {
        return getDelay(TimeUnit.NANOSECONDS) <= 0;
    }

    /**
     * 获取剩余延迟时间（毫秒）
     * @return 剩余延迟时间（毫秒）
     */
    public long getRemainingDelayMs() {
        return getDelay(TimeUnit.MILLISECONDS);
    }

    @Override
    public String toString() {
        return "MessageDelayed{" +
                "id=" + id +
                ", body=" + body +
                ", executeTime=" + executeTime +
                ", remainingMs=" + getRemainingDelayMs() +
                ", expired=" + isExpired() +
                '}';
    }
}